import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.TreeMap;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

public class TestingDictionary extends DefaultHandler {
  public static String LEXELT_TAG_ = "lexelt";
  public static String LEXELT_ITEM_TAG_ = "item";
  public static String CONTEXT_TAG_ = "context";
  public static String HEAD_TAG_ = "head";
  public static String ANSWER_TAG_ = "answer";
  public static String INSTANCE_TAG_ = "instance";
  public static String INSTANCE_ID_TAG_ = "id";
  public static String SENSE_TAG_ = "senseid";

  private final String testFile_;
  private final String testOutputFile_;
  private SenseInventory senseInv_;
  private Writer out_;
  private TreeMap<String,TreeMap<String,Sense>> wordSenses;
  
  private XMLParserState state_ = new XMLParserState(false, 8);
  private Training trainObj_;
  private WordSenseCount wordSenseCount;
  
  public TestingDictionary(String file, String testOutFile, Training trainObj, SenseInventory senseInv, WSD wsdObj) {
    testFile_ = file;
    testOutputFile_ = testOutFile;
    trainObj_ = trainObj;
    wordSenseCount = trainObj_.getWordSenseCount();
    senseInv_ = senseInv;
    wordSenses = senseInv_.getWordSenses();
    parseTestFile();
  }

  public void parseTestFile() {
    String tmpFile = "tmp.xml";
    try {
      FileWriter writer = new FileWriter(tmpFile);
      FileReader reader = new FileReader(testFile_);
      out_ = new FileWriter(testOutputFile_);
      XMLReader xmlr = XMLReaderFactory.createXMLReader();
      xmlr.setContentHandler(this);
      xmlr.setErrorHandler(this);

      BufferedReader br = new BufferedReader(reader);
      WSD.formatXMLfile(br, writer);
      reader.close();
      reader = new FileReader(tmpFile);

      // Parse the intermediate XML file.
      xmlr.parse(new InputSource(reader));
      out_.close();
    } catch (IOException ex) {
      throw new RuntimeException(ex);
    } catch (SAXParseException spe) {
      StringBuffer sb = new StringBuffer(spe.toString());
      sb.append("\n  Line number: " + spe.getLineNumber());
      sb.append("\nColumn number: " + spe.getColumnNumber());
      sb.append("\n Public ID: " + spe.getPublicId());
      sb.append("\n System ID: " + spe.getSystemId() + "\n");
      System.out.println(sb.toString());
    } catch (SAXException se) {
      System.out.println("loadDOM threw " + se);
      se.printStackTrace(System.out);
    }
  }

  @Override
  public void startElement(String uri, String name, String qName,
      Attributes atts) {
    if (qName.equals(LEXELT_TAG_)) {
      state_.setLexelt(atts.getValue(LEXELT_ITEM_TAG_));
    } else if (qName.equals(HEAD_TAG_)) {
      state_.startHeadTag();
    } else if (qName.equals(INSTANCE_TAG_)) {
      state_.resetForInstance(atts.getValue(INSTANCE_ID_TAG_));
    }
  }

  @Override
  public void endElement(String uri, String name, String qName) {
    if (qName.equals(HEAD_TAG_)) {
      state_.endHeadTag();
    } else if (qName.equals("instance")) {
      
      String sense = null;
      
      HashSet<String> neighbors = new HashSet<String>();
      neighbors.addAll(state_.getPrevNList());
      neighbors.addAll(state_.getSuccNList());
//      System.out.println("neighbors:"+neighbors);
      
      int maxCount = -1;
      
      TreeMap<String,Sense> treeMap = wordSenses.get(state_.getLexelt());
      Set<String> keySet = treeMap.keySet();
      for (String key : keySet) {
        int count = 0;
        String gloss = treeMap.get(key).gloss_;
//        System.out.println("sensid:" + key +":"+ gloss);
        String[] words = gloss.split("[ ]");
        for (String word : words) {
          if(neighbors.contains(word)) {
            count++;
            neighbors.remove(word);
          }
        }
        if(count > maxCount) {
          maxCount = count;
          sense = treeMap.get(key).id_;
        }
      }
      if(maxCount == 0) {
        sense = wordSenseCount.getMostFrequentSense(state_.getLexelt());
      }
      String str = state_.getLexelt() + " " + state_.getInstanceId() + " " + sense;
//      System.out.println(str);
//      System.out.println("\n\n");
      try {
        out_.write(str + "\n");
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  @Override
  public void characters(char ch[], int start, int length) {
    String line = new String(ch, start, length);

    CollocationFeature.handleCharacters(line, state_);
  }

  @Override
  public void endDocument() throws SAXException {
    try {
      out_.flush();
      out_.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}
